#include <stdlib.h>
#include <string.h>
#include "ZSysgen.h"
#include "ZTypes.h"
#include "ZClock.h"
#include "httpd.h"
#include "http.h"

#include "Types.h"
#include "HVACControl.h"
#include "eeprom.h"
#include "History.h"
#include "WLAN.h"

// function prototypes
INT16 getStatus_cgi(struct http_request *request);
void jsonEncodeStatus(char jsonData[256]);
INT16 getSettings_cgi(struct http_request *request);
void jsonEncodeSettings(char jsonData[2048]);
INT16 saveSettings_cgi(struct http_request *request);
void jsonDecodeSettings(struct http_request *request, char jsonData[32]);
INT16 saveSchedule_cgi(struct http_request *request);
void jsonDecodeSchedule(struct http_request *request, char jsonData[32]);
error_t getNextToken(char **token, char *end);

// static content
extern const struct staticpage index_html;

extern const struct staticpage ajax_js;
extern const struct staticpage jquery_clockpick_js;
extern const struct staticpage jquery_livequery_js;
extern const struct staticpage jquery_min_js;
extern const struct staticpage jquery_tinysort_js;
extern const struct staticpage jquery_ui_min_js;
extern const struct staticpage site_js_js;
extern const struct staticpage jquery_blockUI_js;
extern const struct staticpage json2_js;

extern const struct staticpage clockpick_css;
extern const struct staticpage jquery_custom_css;
extern const struct staticpage site_css_css;

extern const struct staticpage clock_png;
extern const struct staticpage curStatusBg_png;
extern const struct staticpage logo_png;
extern const struct staticpage remove_png;
extern const struct staticpage temperature_png;
extern const struct staticpage busy_gif;
extern const struct staticpage ui_bg_glass_png;
extern const struct staticpage ui_bg_glass_40_223fff_1x400_png;
extern const struct staticpage ui_bg_glass_40_ffc73d_1x400_png;
extern const struct staticpage ui_bg_gloss_wave_35_333333_500x100_png;
extern const struct staticpage ui_bg_highlight_soft_80_eeeeee_1x100_png;
extern const struct staticpage ui_bg_inset_soft_25_000000_1x100_png;
extern const struct staticpage ui_bg_inset_soft_30_ff7c00_1x100_png;
extern const struct staticpage ui_icons_222222_256x240_png;
extern const struct staticpage ui_icons_cccccc_256x240_png;
extern const struct staticpage ui_icons_ffffff_256x240_png;

// supported mime types
struct mimetype mimetypes[] =
{
	{".html","text/html"},
    {".cgi","application/json"},
	{".js", "text/javascript"},
	{".css", "text/css"},
	{".png", "image/png"},
	{".gif", "image/gif"},
	{"unknown","unknown"}
};
UINT16 NoOfMimeTypes = sizeof(mimetypes)/sizeof(struct mimetype);

// mapping of URLs to content
Webpage website[] =
{
	// Main html content
	{HTTP_PAGE_STATIC, "/", "text/html", &index_html },
	{HTTP_PAGE_STATIC, "/index.html", "text/html", &index_html },

	// JavaScript files
	{HTTP_PAGE_STATIC, "/js/ajax.js", "text/javascript", &ajax_js },
	{HTTP_PAGE_STATIC, "/js/jquery_clockpick.js", "text/javascript", &jquery_clockpick_js },
	{HTTP_PAGE_STATIC, "/js/jquery_livequery.js", "text/javascript", &jquery_livequery_js },
	{HTTP_PAGE_STATIC, "/js/jquery_min.js", "text/javascript", &jquery_min_js },
	{HTTP_PAGE_STATIC, "/js/jquery_tinysort.js", "text/javascript", &jquery_tinysort_js },
	{HTTP_PAGE_STATIC, "/js/jquery_ui_min.js", "text/javascript", &jquery_ui_min_js },
	{HTTP_PAGE_STATIC, "/js/site_js.js", "text/javascript", &site_js_js },
	{HTTP_PAGE_STATIC, "/js/jquery_blockUI.js", "text/javascript", &jquery_blockUI_js },
	{HTTP_PAGE_STATIC, "/js/json2.js", "text/javascript", &json2_js },

	// CSS files
	{HTTP_PAGE_STATIC, "/css/site_css.css", "text/css", &site_css_css },
	{HTTP_PAGE_STATIC, "/css/clockpick.css", "text/css", &clockpick_css },
	{HTTP_PAGE_STATIC, "/css/custom_theme/jquery_custom.css", "text/css", &jquery_custom_css },
	{HTTP_PAGE_STATIC, "/css/site_css.css", "text/css", &site_css_css },

	// Image files
	{HTTP_PAGE_STATIC, "/images/clock.png", "image/png", &clock_png },
	{HTTP_PAGE_STATIC, "/images/curStatusBg.png", "image/png", &curStatusBg_png },
	{HTTP_PAGE_STATIC, "/images/logo.png", "image/png", &logo_png },
	{HTTP_PAGE_STATIC, "/images/remove.png", "image/png", &remove_png },
	{HTTP_PAGE_STATIC, "/images/temperature.png", "image/png", &temperature_png },
	{HTTP_PAGE_STATIC, "/images/busy.gif", "image/gif", &busy_gif },

	// Images files from the custom theme-roller
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_glass.png", "image/png", &ui_bg_glass_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_glass_40_223fff_1x400.png", "image/png", &ui_bg_glass_40_223fff_1x400_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_glass_40_ffc73d_1x400.png", "image/png", &ui_bg_glass_40_ffc73d_1x400_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_gloss_wave_35_333333_500x100.png", "image/png", &ui_bg_gloss_wave_35_333333_500x100_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_highlight_soft_80_eeeeee_1x100.png", "image/png", &ui_bg_highlight_soft_80_eeeeee_1x100_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_inset_soft_25_000000_1x100.png", "image/png", &ui_bg_inset_soft_25_000000_1x100_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_bg_inset_soft_30_ff7c00_1x100.png", "image/png", &ui_bg_inset_soft_30_ff7c00_1x100_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_icons_222222_256x240.png", "image/png", &ui_icons_222222_256x240_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_icons_cccccc_256x240.png", "image/png", &ui_icons_cccccc_256x240_png },
	{HTTP_PAGE_STATIC, "/css/custom_theme/images/ui_icons_ffffff_256x240.png", "image/png", &ui_icons_ffffff_256x240_png },

	// CGI functions for AJAX functions
    {HTTP_PAGE_DYNAMIC, "/getStatus.cgi", "application/json", (struct staticpage *)&getStatus_cgi },
    {HTTP_PAGE_DYNAMIC, "/getSettings.cgi", "application/json", (struct staticpage *)&getSettings_cgi },
    {HTTP_PAGE_DYNAMIC, "/saveSettings.cgi", "application/json", (struct staticpage *)&saveSettings_cgi },
    {HTTP_PAGE_DYNAMIC, "/saveSchedule.cgi", "application/json", (struct staticpage *)&saveSchedule_cgi },
	{0, NULL, NULL, NULL }
};

INT16 getStatus_cgi(struct http_request *request)
{
	char jsonData[256];
	INT8 strDate[64];
	INT8 strSize[16];
	
	jsonEncodeStatus(jsonData);
	
	__http_date(strDate, sizeof(strDate));
	__http_itoal(strlen(jsonData), strSize);
	
	if ( request->keepalive)
		http_add_header(request,HTTP_HDR_CONNECTION, "Keep-Alive");
	else
		http_add_header(request,HTTP_HDR_CONNECTION, "close");
	
	http_add_header(request,HTTP_HDR_CONTENT_TYPE, "application/json");
	http_add_header(request,HTTP_HDR_DATE, strDate);
	http_add_header(request,HTTP_HDR_CONTENT_LENGTH, strSize);
	
	if(http_output_reply(request, HTTP_200_OK) < 0)
		return -1;
	
	__http_write(request, jsonData, strlen(jsonData));
	return OK;
}

void jsonEncodeStatus(char jsonData[256])
{
	RZK_CLOCKPARAMS_t sysTime;
	temp_t currentTemp, currentSetTemp;
	hvac_state_t currentMode;
	history_log_t history;
	char *currentTime;
	char itoaStr[10];

	RZKGetClock(&sysTime);
	currentTemp = getCurTemp();
	currentMode = getCurHVACState();
	currentSetTemp = getSetTemp();

	jsonData[0] = '\0';
	// status (19 characters)
	strcat(jsonData, "{\"result\":\"success\"");

	// current inside temperature (19 characters)
	strcat(jsonData, ",\"temperature\":");
	itoa(currentTemp, itoaStr, 10);
	strcat(jsonData, itoaStr);

	// current HVAC state (21 characters)
	strcat(jsonData, ",\"hvacMode\":\"");
	if (currentMode == HEATING)
		strcat(jsonData, "Heating");
	else if (currentMode == COOLING)
		strcat(jsonData, "Cooling");
	else
		strcat(jsonData, "Off");
	strcat(jsonData, "\"");

	// current inside temperature (16 characters)
	strcat(jsonData, ",\"setTemp\":");
	itoa(currentSetTemp, itoaStr, 10);
	strcat(jsonData, itoaStr);

	// current time (29 characters)
	strcat(jsonData, ",\"time\":\"");
	itoa(sysTime.uCurr_Month, itoaStr, 10);
	strcat(jsonData, itoaStr);
	strcat(jsonData, "/");
	itoa(sysTime.uCurr_Date, itoaStr, 10);
	strcat(jsonData, itoaStr);
	strcat(jsonData, "/");
	itoa(sysTime.uCurr_Year, itoaStr, 10);
	strcat(jsonData, itoaStr);

	strcat(jsonData, " ");

	if (sysTime.uCurr_Hour == 0)
		strcat(jsonData, "12");
	else
	{
		itoa(sysTime.uCurr_Hour > 12 ? sysTime.uCurr_Hour - 12 : sysTime.uCurr_Hour, itoaStr, 10);
		strcat(jsonData, itoaStr);
	}
	strcat(jsonData, ":");
	if (sysTime.uCurr_Minute < 10)
		strcat(jsonData, "0");
	itoa(sysTime.uCurr_Minute, itoaStr, 10);
	strcat(jsonData, itoaStr);

	strcat(jsonData, " ");

	strcat(jsonData, sysTime.uCurr_Hour > 12 ? "PM" : "AM");
	strcat(jsonData, "\"");

	history = getHistoryLog(ALL_TIME);
	// cool run time (23 characters)
	strcat(jsonData, ",\"ACRuntime\":");
	itoa(history.ACRuntime, itoaStr, 10);
	strcat(jsonData, itoaStr);
	// heat run time (25 characters)
	strcat(jsonData, ",\"HeatRuntime\":");
	itoa(history.HeatRuntime, itoaStr, 10);
	strcat(jsonData, itoaStr);
	// fan run time (24 characters)
	strcat(jsonData, ",\"FanRuntime\":");
	itoa(history.FanRuntime, itoaStr, 10);
	strcat(jsonData, itoaStr);

	strcat(jsonData, "}");
}

INT16 getSettings_cgi(struct http_request *request)
{
	char jsonData[2048];
	INT8 strDate[64];
	INT8 strSize[16];
	
	jsonEncodeSettings(jsonData);
	
	__http_date(strDate, sizeof(strDate));
	__http_itoal(strlen(jsonData), strSize);
	
	if ( request->keepalive)
		http_add_header(request,HTTP_HDR_CONNECTION, "Keep-Alive");
	else
		http_add_header(request,HTTP_HDR_CONNECTION, "close");
	
	http_add_header(request,HTTP_HDR_CONTENT_TYPE, "application/json");
	http_add_header(request,HTTP_HDR_DATE, strDate);
	http_add_header(request,HTTP_HDR_CONTENT_LENGTH, strSize);
	
	if(http_output_reply(request, HTTP_200_OK) < 0)
		return -1;
	
	__http_write(request, jsonData, strlen(jsonData));
	return OK;
}

void jsonEncodeSettings(char jsonData[2048])
{
	int i, j;
	char *currentTime;
	char itoaStr[10];
	eeprom_settings_t settings;

	// get current settings
	eepromGetSettings(&settings);

	jsonData[0] = '\0';
	// status (19 characters)
	strcat(jsonData, "{\"result\":\"success\"");

	// mac address (96 characters)
	for (i = 0; i < 6; i++)
	{
		char macAddrStr[3];
		char idx[2];
		itoa(settings.wlanSettings.macAddr[i], macAddrStr, 16);
		itoa(i+1, idx, 10);
		strcat(jsonData, ",\"macAddr");
		strcat(jsonData, idx);
		strcat(jsonData, "\":\"");
		if (settings.wlanSettings.macAddr[i] < 16)
			strcat(jsonData, "0");
		strcat(jsonData, macAddrStr);
		strcat(jsonData, "\"");
	}

	// DHCP enabled (20 characters)
	strcat(jsonData, ",\"dhcpEnabled\":\"");
	strcat(jsonData, settings.wlanSettings.dhcpEnabled == 1 ? "Yes" : "No");
	strcat(jsonData, "\"");

	// IP address (56 characters)
	for (i = 0; i < 4; i++)
	{
		char ipAddrStr[4];
		unsigned char part;
		char idx[2];
		part = (settings.wlanSettings.ipAddr >> i) & 0xFF;
		itoa(part, ipAddrStr, 10);
		itoa(i+1, idx, 10);
		strcat(jsonData, ",\"ipAddr");
		strcat(jsonData, idx);
		strcat(jsonData, "\":");
		strcat(jsonData, ipAddrStr);
	}

	// subnet mask (64 characters)
	for (i = 0; i < 4; i++)
	{
		char subnetStr[4];
		unsigned char part;
		char idx[2];
		part = (settings.wlanSettings.inetMask >> i) & 0xFF;
		itoa(part, subnetStr, 10);
		itoa(i+1, idx, 10);
		strcat(jsonData, ",\"inetMask");
		strcat(jsonData, idx);
		strcat(jsonData, "\":");
		strcat(jsonData, subnetStr);
	}

	// gateway address (76 characters)
	for (i = 0; i < 4; i++)
	{
		char gwStr[4];
		unsigned char part;
		char idx[2];
		part = (settings.wlanSettings.gatewayAddr >> i) & 0xFF;
		itoa(part, gwStr, 10);
		itoa(i+1, idx, 10);
		strcat(jsonData, ",\"gatewayAddr");
		strcat(jsonData, idx);
		strcat(jsonData, "\":");
		strcat(jsonData, gwStr);
	}

	// DNS address (56 characters)
	for (i = 0; i < 4; i++)
	{
		char dnsStr[4];
		unsigned char part;
		char idx[2];
		part = (settings.wlanSettings.dnsAddr >> i) & 0xFF;
		itoa(part, dnsStr, 10);
		itoa(i+1, idx, 10);
		strcat(jsonData, ",\"dnsAddr");
		strcat(jsonData, idx);
		strcat(jsonData, "\":");
		strcat(jsonData, dnsStr);
	}

	// SSID (42 characters)
	strcat(jsonData, ",\"ssid\":\"");
	strcat(jsonData, settings.wlanSettings.ssid);
	strcat(jsonData, "\"");

	// WEP key (38 characters)
	strcat(jsonData, ",\"wepKey\":\"");
	for (i = 0; i < settings.wlanSettings.wepKeyLen; i++)
	{
		char wepKeyStr[3];
		char idx[2];
		itoa(settings.wlanSettings.wepKey[i], wepKeyStr, 16);
		if (settings.wlanSettings.wepKey[i] < 16)
			strcat(jsonData, "0");
		strcat(jsonData, wepKeyStr);
	}
	strcat(jsonData, "\"");

	// hold temperature (17 characters)
	itoa(settings.hvacSettings.setTemp, itoaStr, 10);
	strcat(jsonData, ",\"manualTemp\":");
	strcat(jsonData, itoaStr);

	// temperature variance (17 characters)
	itoa(settings.hvacSettings.tempVariance, itoaStr, 10);
	strcat(jsonData, ",\"tempVariance\":");
	strcat(jsonData, itoaStr);

	// HVAC mode (21 characters)
	strcat(jsonData, ",\"setHVACMode\":\"");
	if (settings.hvacSettings.setHVACMode == HEAT)
		strcat(jsonData, "Heat");
	else if (settings.hvacSettings.setHVACMode == AC)
		strcat(jsonData, "Cool");
	else
		strcat(jsonData, "Off");
	strcat(jsonData, "\"");

	// fan mode (20 characters)
	strcat(jsonData, ",\"setFanMode\":\"");
	if (settings.hvacSettings.setFanMode == FAN_ON)
		strcat(jsonData, "On");
	else
		strcat(jsonData, "Auto");
	strcat(jsonData, "\"");

	// heater type (26 characters)
	strcat(jsonData, ",\"myHeaterType\":\"");
	if (settings.hvacSettings.myHeaterType == ELECTRIC)
		strcat(jsonData, "Electric");
	else
		strcat(jsonData, "Gas");
	strcat(jsonData, "\"");

	// temperature units (15 characters)
	strcat(jsonData, ",\"tempUnit\":\"");
	strcat(jsonData, settings.hvacSettings.tempUnit == CELSIUS ? "C" : "F");
	strcat(jsonData, "\"");

	// hold or schedule mode (20 characters)
	strcat(jsonData, ",\"opMode\":\"");
	if (settings.hvacSettings.opMode == SCHEDULE_ACTIVE)
		strcat(jsonData, "Schedule");
	else
		strcat(jsonData, "Manual");
	strcat(jsonData, "\"");

	// polling interval (19 characters)
	itoa(settings.hvacSettings.pollInterval, itoaStr, 10);
	strcat(jsonData, ",\"pollInterval\":");
	strcat(jsonData, itoaStr);

	// temperature offset (17 characters)
	itoa(settings.tempOffset, itoaStr, 10);
	strcat(jsonData, ",\"tempOffset\":");
	strcat(jsonData, itoaStr);

	// internet time enabled (23 characters)
	strcat(jsonData, ",\"autoTimeSync\":");
	if (settings.timeSettings.internetTimeEnabled)
		strcat(jsonData, "true");
	else
		strcat(jsonData, "false");

	// daylight savings time enabled (32 characters)
	strcat(jsonData, ",\"daylightSavingEnabled\":");
	if (settings.timeSettings.daylightSavingEnabled)
		strcat(jsonData, "true");
	else
		strcat(jsonData, "false");

	// time server address (73 characters)
	strcat(jsonData, ",\"timeServerAddress\":\"");
	strcat(jsonData, settings.timeSettings.timeServerAddress);
	strcat(jsonData, "\"");

	// time zone (22 characteers)
	strcat(jsonData, ",\"timeZone\":\"");
	if (settings.timeSettings.timeZone == CENTRAL)
		strcat(jsonData, "central");
	else if (settings.timeSettings.timeZone == PACIFIC)
		strcat(jsonData, "pacific");
	else if (settings.timeSettings.timeZone == MOUNTAIN)
		strcat(jsonData, "mountain");
	else if (settings.timeSettings.timeZone == EASTERN)
		strcat(jsonData, "eastern");
	strcat(jsonData, "\"");

	// schedule (874 characters for 7 days with 5 temp changes per day)
	strcat(jsonData, ",\"schedule\":[");
	for (i = 0; i < NUM_SCHEDULE_DAYS; i++)
	{
		// process each day
		if (i != 0)
			strcat(jsonData, ",");
		strcat(jsonData, "[");
		for (j = 0; j < MAX_DAILY_SCHED_CHANGES; j++)
		{
			// set temp 0 means schedule slot not used
			if (settings.schedule[i].changes[j].temp == 0)
				break;

			// process each time slot
			if (j != 0)
				strcat(jsonData, ",");
			strcat(jsonData, "{\"temp\":");
			itoa(settings.schedule[i].changes[j].temp, itoaStr, 10);
			strcat(jsonData, itoaStr);
			strcat(jsonData, ",\"time\":");
			itoa(settings.schedule[i].changes[j].time, itoaStr, 10);
			strcat(jsonData, itoaStr);
			strcat(jsonData, "}");
		}
		strcat(jsonData, "]");
	}
	strcat(jsonData, "]");

	strcat(jsonData, "}");
}

INT16 saveSettings_cgi(struct http_request *request)
{
	char jsonData[32];
	INT8 strDate[64];
	INT8 strSize[16];

	jsonDecodeSettings(request, jsonData);

	__http_date(strDate, sizeof(strDate));
	__http_itoal(strlen(jsonData), strSize);

	if ( request->keepalive)
		http_add_header(request,HTTP_HDR_CONNECTION, "Keep-Alive");
	else
		http_add_header(request,HTTP_HDR_CONNECTION, "close");

	http_add_header(request,HTTP_HDR_CONTENT_TYPE, "application/json");
	http_add_header(request,HTTP_HDR_DATE, strDate);
	http_add_header(request,HTTP_HDR_CONTENT_LENGTH, strSize);

	if(http_output_reply(request, HTTP_200_OK) < 0)
		return -1;
	
	__http_write(request, jsonData, strlen(jsonData));
	return OK;
}

void jsonDecodeSettings(struct http_request *request, char jsonData[32])
{
	char *token, *end;
	unsigned int number = 0, i;
	eeprom_settings_t settings;
	error_t error = SUCCESS;
	BOOL newNetworkSettings = FALSE;
	UINT8 tempWepKey[13];

	// get current settings
	eepromGetSettings(&settings);

	token = request->buffer;
	end = request->buffer + HTTP_REQUEST_BUF;
	// advance to beginning of json encoded string
	while (token < end)
	{
		if (*token == '{')
			break;
		token++;
	}
	if (token >= end)
		error = GENERAL_ERROR;
	*token = '\0';

	// MAC address
	for (i = 0; i < 6; i++)
	{
		char macAddrStr[] = "macAddr ";
		if (error)
			break;

		error = getNextToken(&token, end);
		itoa(i + 1, macAddrStr+7, 10);
		if (!error && strcmp(token, macAddrStr) == 0 && !(error = getNextToken(&token, end)))
		{
			sscanf(token, "%x", &number);
			settings.wlanSettings.macAddr[i] = number;
		}
		else
			error = GENERAL_ERROR;
	}

	// DHCP enabled
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "dhcpEnabled") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "Yes") == 0)
			settings.wlanSettings.dhcpEnabled = 1;
		else if (!error && strcmp(token, "No") == 0)
			settings.wlanSettings.dhcpEnabled = 0;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// IP address
	settings.wlanSettings.ipAddr = 0;
	for (i = 0; i < 4; i++)
	{
		char ipAddrStr[] = "ipAddr ";
		if (error)
			break;

		error = getNextToken(&token, end);
		itoa(i + 1, ipAddrStr+6, 10);
		if (!error && strcmp(token, ipAddrStr) == 0 && !(error = getNextToken(&token, end)))
		{
			sscanf(token, "%d", &number);
			settings.wlanSettings.ipAddr |= (number << i);
		}
		else
			error = GENERAL_ERROR;
	}
	
	// subnet mask
	settings.wlanSettings.inetMask = 0;
	for (i = 0; i < 4; i++)
	{
		char subnetMaskStr[] = "inetMask ";
		if (error)
			break;

		error = getNextToken(&token, end);
		itoa(i + 1, subnetMaskStr+8, 10);
		if (!error && strcmp(token, subnetMaskStr) == 0 && !(error = getNextToken(&token, end)))
		{
			sscanf(token, "%d", &number);
			settings.wlanSettings.inetMask |= (number << i);
		}
		else
			error = GENERAL_ERROR;
	}

	// gateway address
	settings.wlanSettings.gatewayAddr = 0;
	for (i = 0; i < 4; i++)
	{
		char gwAddrStr[] = "gatewayAddr ";
		if (error)
			break;

		error = getNextToken(&token, end);
		itoa(i + 1, gwAddrStr+11, 10);
		if (!error && strcmp(token, gwAddrStr) == 0 && !(error = getNextToken(&token, end)))
		{
			sscanf(token, "%d", &number);
			settings.wlanSettings.gatewayAddr |= (number << i);
		}
		else
			error = GENERAL_ERROR;
	}

	// DNS address
	settings.wlanSettings.dnsAddr = 0;
	for (i = 0; i < 4; i++)
	{
		char dnsAddrStr[] = "dnsAddr ";
		if (error)
			break;

		error = getNextToken(&token, end);
		itoa(i + 1, dnsAddrStr+7, 10);
		if (!error && strcmp(token, dnsAddrStr) == 0 && !(error = getNextToken(&token, end)))
		{
			sscanf(token, "%d", &number);
			settings.wlanSettings.dnsAddr |= (number << i);
		}
		else
			error = GENERAL_ERROR;
	}

	// SSID
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "ssid") == 0 && !(error = getNextToken(&token, end)))
	{
		if(strncmp(settings.wlanSettings.ssid, token, 33) != 0)
		{
			newNetworkSettings = TRUE;
		}
		strncpy(settings.wlanSettings.ssid, token, 33);
		settings.wlanSettings.ssid[32] = '\0';
	}
	else
		error = GENERAL_ERROR;

	// WEP key
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "wepKey") == 0 && !(error = getNextToken(&token, end)))
	{
		char tempChar[3];
		int i;
		//Copy the old WEP to a temp
		memcpy(tempWepKey, 0, 13);
		memcpy(tempWepKey, settings.wlanSettings.wepKey, settings.wlanSettings.wepKeyLen);
		
		for(i = 0; i<strlen(token); i+=2)
		{
			tempChar[0] = token[i];
			tempChar[1] = token[i+1];
			tempChar[2] = '\0';
			sscanf(tempChar, "%x", &number);
			settings.wlanSettings.wepKey[i/2] = number;
		}
		//TODO: Need to grab two hex characters at a time and store them as UINT8's to wlanSettings.wepKey
		//TODO: Debug and see if newNetworkSettings is getting set when it should
	//	strncpy((char *)settings.wlanSettings.wepKey, token, 13);
		settings.wlanSettings.wepKeyLen = strlen(token) > 13 ? 13 : strlen(token);
		if(strncmp(settings.wlanSettings.wepKey, tempWepKey, settings.wlanSettings.wepKeyLen) != 0)
		{
			newNetworkSettings = TRUE;
		}
	}
	else
		error = GENERAL_ERROR;

	// hold temperature
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "manualTemp") == 0 && !(error = getNextToken(&token, end)))
	{
		sscanf(token, "%d", &number);
		settings.hvacSettings.setTemp = number;
	}
	else
		error = GENERAL_ERROR;
	
	// temperature variance
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "tempVariance") == 0 && !(error = getNextToken(&token, end)))
	{
		sscanf(token, "%d", &number);
		settings.hvacSettings.tempVariance = number;
	}
	else
		error = GENERAL_ERROR;
	
	// HVAC mode
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "setHVACMode") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "Heat") == 0)
			settings.hvacSettings.setHVACMode = HEAT;
		else if (!error && strcmp(token, "Cool") == 0)
			settings.hvacSettings.setHVACMode = AC;
		else if (!error && strcmp(token, "Off") == 0)
			settings.hvacSettings.setHVACMode = OFF;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// fan mode
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "setFanMode") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "Auto") == 0)
			settings.hvacSettings.setFanMode = FAN_AUTO;
		else if (!error && strcmp(token, "On") == 0)
			settings.hvacSettings.setFanMode = FAN_ON;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// heater type
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "myHeaterType") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "Electric") == 0)
			settings.hvacSettings.myHeaterType = ELECTRIC;
		else if (!error && strcmp(token, "Gas") == 0)
			settings.hvacSettings.myHeaterType = GAS;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;
	
	// temperature units
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "tempUnit") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "C") == 0)
			settings.hvacSettings.tempUnit = CELSIUS;
		else if (!error && strcmp(token, "F") == 0)
			settings.hvacSettings.tempUnit = FAHRENHEIT;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// hold or schedule mode
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "opMode") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "Schedule") == 0)
			settings.hvacSettings.opMode = SCHEDULE_ACTIVE;
		else if (!error && strcmp(token, "Manual") == 0)
			settings.hvacSettings.opMode = HOLD;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// polling interval
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "pollInterval") == 0 && !(error = getNextToken(&token, end)))
	{
		sscanf(token, "%d", &number);
		settings.hvacSettings.pollInterval = number;
	}
	else
		error = GENERAL_ERROR;

	// temperature offset
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "tempOffset") == 0 && !(error = getNextToken(&token, end)))
	{
		sscanf(token, "%d", &number);
		settings.tempOffset = number;
	}
	else
		error = GENERAL_ERROR;

	// internet time enabled
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "autoTimeSync") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "true") == 0)
			settings.timeSettings.internetTimeEnabled = TRUE;
		else if (!error && strcmp(token, "false") == 0)
			settings.timeSettings.internetTimeEnabled = FALSE;
	}
	else
		error = GENERAL_ERROR;

	// daylight savings time enabled
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "daylightSavingEnabled") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "true") == 0)
			settings.timeSettings.daylightSavingEnabled = TRUE;
		else if (!error && strcmp(token, "false") == 0)
			settings.timeSettings.daylightSavingEnabled = FALSE;
	}
	else
		error = GENERAL_ERROR;

	// time server address
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "timeServerAddress") == 0 && !(error = getNextToken(&token, end)))
	{
		strncpy((char *)settings.timeSettings.timeServerAddress, token, MAX_TIME_SERVER_CHARS);
		settings.timeSettings.timeServerAddress[MAX_TIME_SERVER_CHARS-1] = '\0';
	}
	else
		error = GENERAL_ERROR;

	// time zone
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "timeZone") == 0 && !(error = getNextToken(&token, end)))
	{
		if (!error && strcmp(token, "central") == 0)
			settings.timeSettings.timeZone = CENTRAL;
		else if (!error && strcmp(token, "pacific") == 0)
			settings.timeSettings.timeZone = PACIFIC;
		else if (!error && strcmp(token, "mountain") == 0)
			settings.timeSettings.timeZone = MOUNTAIN;
		else if (!error && strcmp(token, "eastern") == 0)
			settings.timeSettings.timeZone = EASTERN;
		else
			error = GENERAL_ERROR;
	}
	else
		error = GENERAL_ERROR;

	// persist settings if everything was valid
	if (!error)
		error = eepromSaveSettings(&settings);

	//Notify of new network settings
//	if(newNetworkSettings == TRUE)
//	{
//		alertNewNetworkSettings();
//	}

	jsonData[0] = '\0';
	if (!error)
		strcat(jsonData, "{\"result\":\"success\"}");
	else
		strcat(jsonData, "{\"result\":\"error\"}");
}


INT16 saveSchedule_cgi(struct http_request *request)
{
	char jsonData[32];
	INT8 strDate[64];
	INT8 strSize[16];

	jsonDecodeSchedule(request, jsonData);

	__http_date(strDate, sizeof(strDate));
	__http_itoal(strlen(jsonData), strSize);

	if ( request->keepalive)
		http_add_header(request,HTTP_HDR_CONNECTION, "Keep-Alive");
	else
		http_add_header(request,HTTP_HDR_CONNECTION, "close");

	http_add_header(request,HTTP_HDR_CONTENT_TYPE, "application/json");
	http_add_header(request,HTTP_HDR_DATE, strDate);
	http_add_header(request,HTTP_HDR_CONTENT_LENGTH, strSize);

	if(http_output_reply(request, HTTP_200_OK) < 0)
		return -1;
	
	__http_write(request, jsonData, strlen(jsonData));
	return OK;
}

void jsonDecodeSchedule(struct http_request *request, char jsonData[32])
{
	char *token, *end;
	unsigned int number = 0, i;
	eeprom_settings_t settings;
	error_t error = SUCCESS;

	// get current settings
	eepromGetSettings(&settings);

	token = request->buffer;
	end = request->buffer + HTTP_REQUEST_BUF;
	// advance to beginning of json encoded string
	while (token < end)
	{
		if (*token == '{')
			break;
		token++;
	}
	if (token >= end)
		error = GENERAL_ERROR;
	*token = '\0';

	// schedule
	memset(settings.schedule, 0, sizeof(settings.schedule));
	error = getNextToken(&token, end);
	if (!error && strcmp(token, "schedule") == 0)
	{
		int i, j;

		// advance to the first day
		while (token < end)
		{
			if (*token == '[')
				break;
			token++;
		}
		if (token >= end)
			error = GENERAL_ERROR;
		token++;

		// process each day
		for (i = 0; i < NUM_SCHEDULE_DAYS; i++)
		{
			// each day starts with a [
			if (error || token >= end || *token != '[')
			{
				error = GENERAL_ERROR;
				break;
			}
			token++;
			// an empty time slot will have just a ]
			if (*token == ']')
			{
				// skip ],
				token += 2;
				continue;
			}

			// process each time slot
			for (j = 0; j < MAX_DAILY_SCHED_CHANGES; j++)
			{
				// each time slot starts with a {
				if (error || token >= end || *token != '{')
				{
					error = GENERAL_ERROR;
					break;
				}
				*token = '\0';
				
				// process each time slot
				error = getNextToken(&token, end);
				if (!error && strcmp(token, "temp") == 0 && !(error = getNextToken(&token, end)))
				{
					sscanf(token, "%d", &number);
					settings.schedule[i].changes[j].temp = number;
				}
				else
				{
					error = GENERAL_ERROR;
					break;
				}

				error = getNextToken(&token, end);
				if (!error && strcmp(token, "time") == 0 && !(error = getNextToken(&token, end)))
				{
					sscanf(token, "%d", &number);
					settings.schedule[i].changes[j].time = number;
				}
				else
				{
					error = GENERAL_ERROR;
					break;
				}

				// skip }
				while (token < end)
				{
					if (*token == '}')
						break;
					token++;
				}
				if (token >= end)
				{
					error = GENERAL_ERROR;
					break;
				}
				token++;

				// check for another time slot for the current day
				if (*token == ',')
					token++;
				else
					break;
			}

			// skip ],
			token += 2;
		}
	}
	else
		error = GENERAL_ERROR;

	// persist settings if everything was valid
	if (!error)
		error = eepromSaveSettings(&settings);

	//Notify of new network settings
//	if(newNetworkSettings == TRUE)
//	{
//		alertNewNetworkSettings();
//	}

	jsonData[0] = '\0';
	if (!error)
		strcat(jsonData, "{\"result\":\"success\"}");
	else
		strcat(jsonData, "{\"result\":\"error\"}");
}

error_t getNextToken(char **token, char *end)
{
	int idx;

	// skip to the beginning of the next token
	while (**token != '\0')
	{
		if (*token >= end)
			return GENERAL_ERROR;
		(*token)++;
	}
	(*token)++;

	// skip the { } , "  : [ ] characters
	while (**token == '{' || **token == '}' || **token == ',' ||
		**token == '"' || **token == ' ' || **token == ':' ||
		**token == '[' || **token == ']')
	{
		if (*token >= end)
			return GENERAL_ERROR;
		(*token)++;
	}

	idx = 0;
	// change next } , " : ] to \0
	while ((*token)[idx] != '}' && (*token)[idx] != ',' && (*token)[idx] != '"' &&
		(*token)[idx] != ':' && (*token)[idx] != ']' && (*token)[idx] != '\0')
	{
		if ((*token + idx) >= end)
			return GENERAL_ERROR;
		idx++;
	}
	(*token)[idx] = '\0';

	return SUCCESS;
}